package com.demo.controller;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.demo.dto.NotifyDTO;
import lombok.*;
import org.junit.Test;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.SocketOption;
import java.net.URI;
import java.nio.file.Paths;
import java.util.Objects;

@RestController
@Validated
public class AppController implements ResourceLoaderAware {

    private ResourceLoader resourceLoader;

    @GetMapping("/test")
    public String test() {
        return "test";
    }

    @GetMapping("/test1")
    public String test1() {
        return "test1";
    }

    @PostMapping("/upload")
    public String test2(MultipartFile file) throws IOException {
        System.out.println(file);
        String uploadDir = "C:/Users/Terminator-J/Downloads";
        file.transferTo(Paths.get(uploadDir.concat(Objects.requireNonNull(file.getOriginalFilename()))));
        return "test2";
    }

    @GetMapping("/test3")
    public String test3(@NotNull String name) {
        System.out.println(name);
        return name;
    }

    @GetMapping("/test4")
    public String test4(@RequestParam("name") String name) {
        System.out.println(name);
        return name;
    }

    /*
        @NotNull： 不能为null，但可以为""，如：(""," ","   ")
        @NotEmpty：不能为null，而且长度必须大于0，不能为""，如：(" ","  "); 如果是集合类型的话，集合大小不能为0
        @NotBlank：只能作用在String上，不能为null，而且调用trim()后，长度必须大于0  即：必须有实际字符
     */
    @PostMapping(value = "/test5", produces = "application/json")
    public UserDTO test5(@Valid @RequestBody UserDTO user) {
        System.out.println(user);
        return user;
    }

    // CORS参考文档：
    // https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
    // https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-cors
    //
    // 原因：浏览器禁止对当前源外的资源进行AJAX调用)解决方法：如果项目没有使用security,直接加@CrossOrigin注解在控制器类上面或控制器方法上即可。
    //
    // 测试命令： curl -v -H "Access-Control-Request-Method: GET" -H "Origin: http://localhost:9999" -X OPTIONS http://localhost:8080/app/cros
    // 使用idea的http client测试的话，会看不到响应的http协议头，分析不了，只能用curl
    //
    // @CrossOrigin 默认 允许跨域请求的方法是：GET、POST、OPTIONS
    // 如果想要配置允许更多的http方法，要配置@CrossOrigin的methods属性，这个属性的配置会覆盖掉默认值。
    // 更多跨域的配置，请看@CrossOrigin注解的源码。
    //
    // spring mvc 还支持其它的方式配置 CROS跨域请求，请参考官方文档：
    // https://docs.spring.io/spring/docs/5.2.2.RELEASE/spring-framework-reference/web.html#mvc-cors-global-java
    // https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-cors
    @RequestMapping(value = "/cors", produces = "text/plain;charset=UTF-8")
    @CrossOrigin(methods = {RequestMethod.GET, RequestMethod.OPTIONS, RequestMethod.PUT})
    public String testCors() {
        return "跨域访问成功";
    }

    @RequestMapping(value = "/notify")
    @CrossOrigin
    public ResponseEntity<NotifyDTO> testNotify(@Validated({NotifyDTO.add.class}) @RequestBody NotifyDTO notifyDTO, @Valid @NotBlank String test) {
        System.out.println(notifyDTO);
//        return JSONObject.toJSONString(notifyDTO);
        return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(notifyDTO);
    }

    @GetMapping("/getfile")
    @CrossOrigin
    public ResponseEntity<Resource> testGetFile() throws MalformedURLException {
        Resource file = new UrlResource("https://www.baidu.com/img/baidu_resultlogo@2.png");
        System.out.println(file.getFilename());

        // 如果直接返回Resource时，响应http的content_type会变化
        // 控制浏览器强制提示下载，不打开文件。
        return ResponseEntity.ok().contentType(MediaType.APPLICATION_OCTET_STREAM).body(file);
    }

    /*
        在浏览器打开并显示图片
     */
    @GetMapping("/getfile2")
    @CrossOrigin
    public ResponseEntity<Resource> testGetFile2() {
//        Resource file = resourceLoader.getResource("https://www.baidu.com/img/baidu_resultlogo@2.png");
        Resource file = resourceLoader.getResource("file:C:/Users/Terminator-J/Pictures/logo.png");

        System.out.println(file.getFilename());

        // 如果直接返回Resource时，响应http的content_type会变化
        return ResponseEntity.ok().contentType(MediaType.IMAGE_PNG).body(file);
    }

    /*
        在浏览器中打开会提示下载窗口
        增加Content-Disponsition的头部，浏览器才会识别文件名
     */
    @GetMapping("/getfile3")
    @CrossOrigin
    public ResponseEntity<Resource> testGetFile3() {
//        Resource file = resourceLoader.getResource("https://www.baidu.com/img/baidu_resultlogo@2.png");
        Resource file = resourceLoader.getResource("file:C:/Users/Terminator-J/Pictures/logo.png");

        System.out.println(file.getFilename());

        // 如果直接返回Resource时，响应http的content_type会变化
        return ResponseEntity.ok()
                // 控制浏览器强制提示下载，不打开文件
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                // 增加Content-Disponsition的头部，浏览器才会识别文件名
                .header(HttpHeaders.CONTENT_DISPOSITION,
                        "attachment; filename=\"" + file.getFilename() + "\"")
                .body(file);
    }

    /*
        在浏览器中打开会提示下载窗口
        增加Content-Disponsition的头部，浏览器才会识别文件名
        使用UriComponents工具类 构造 url
     */
    @GetMapping("/getfile4")
    @CrossOrigin
    public ResponseEntity<Resource> testGetFile4() {
        String filename = "小黄脸.png";
        //@formatter:off
        //UriComponents工具类
        UriComponents uriComponents = UriComponentsBuilder
                .fromUriString("file:C:/Users/Terminator-J/Pictures/{filename}")
                .buildAndExpand(filename)
                .encode();// 如果可能含有中文，需要encode
        //@formatter:on

//        Resource file = resourceLoader.getResource("https://www.baidu.com/img/baidu_resultlogo@2.png");
//        Resource file = resourceLoader.getResource("file:C:/Users/Terminator-J/Pictures/logo.png");
        Resource file = resourceLoader.getResource(uriComponents.toString());
        System.out.println(file.getFilename());

        // 如果直接返回Resource时，响应http的content_type会变化
        return ResponseEntity.ok()
                .contentType(MediaType.IMAGE_PNG)
                // 控制浏览器强制提示下载，不打开文件
//                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                // 增加Content-Disponsition的头部，浏览器才会识别文件名
                .header(HttpHeaders.CONTENT_DISPOSITION,
                        "attachment; filename=\"" + file.getFilename() + "\"")
                .body(file);
    }

    //演示trim()
    @Test
    public void testTrim() {
        String str = "    a    a    b   c    ";
        System.out.println("Before trim() -> [" + str + "] [str.length]:" + str.length());
        System.out.println("After trim() -> [" + str.trim() + "] [str.length]:" + str.trim().length());
    }

    @GetMapping(value = "/test6", produces = "application/json")
    public UserDTO test6(UserDTO user) {
        System.out.println(user);
//        return user;
        return UserDTO.builder().name("Zheng").age(18).gender("Man").build();
    }

    @GetMapping(value = "/test7", produces = "application/json")
    public Object test7() throws IOException {
        Resource resource = resourceLoader.getResource("http://localhost:8080/springmvc/app/test6");
        resource.getInputStream();
        val parse = JSONObject.parse(resource.getInputStream().readAllBytes());
        return parse;
    }

    // 使用RestTemplate调用http请求
    // 注意 RestTemplate 内部 也有使用 HttpMessageConverter 转换 http请求正文的
    // 遇到json的字符串数据的正文的转换，需要额外添加一个HttpMessageConverter，下面使用FastJsonHttpMessageConverter
    @GetMapping(value = "/test8", produces = "application/json")
    public Object test8() {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new FastJsonHttpMessageConverter());
        UserDTO userForObj = restTemplate.getForObject("http://localhost:8080/springmvc/app/test6", UserDTO.class);
        return userForObj;
    }

    // 使用WebClinet 内部发送http请求
    @GetMapping("/webclient")
    public Object testWebClient() {
        WebClient webClient = WebClient.builder().build();
        UserDTO userDTO = webClient.get()
                .uri("http://127.0.0.1:8080/springmvc/app/test6")
                .exchange()
                .flatMap(clientResponse -> clientResponse.bodyToMono(UserDTO.class))
                .block();

        Resource resource = webClient.get()
                .uri("https://www.baidu.com/img/baidu_resultlogo@2.png")
                .exchange()
                .flatMap(clientResponse -> clientResponse.bodyToMono(Resource.class))
                .block();
        return resource;
    }


    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }
}

@Getter
@Setter
@NoArgsConstructor
@ToString
@Builder
@AllArgsConstructor
class UserDTO {
    //通过lombok提供的注解创建对应getter、setter、无参构造方法、toString方法
    @NotNull
    private String name;
    private int age;
    private String gender;
}
